package com.eptok.gw.szcups.socket.client.factory;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.eptok.gw.szcups.common.GateWayConstant;
import com.eptok.gw.szcups.socket.client.agent.ClientAgent;
import com.eptok.gw.szcups.socket.client.agent.ClientAgentAsynImpl;
import com.eptok.gw.szcups.socket.client.agent.ClientConfig;
import com.eptok.gw.szcups.socket.client.agent.Reconnectable;

/**
 *@author:heqishan, Email:heqishan@gmail.com
 *2013-3-5 上午10:53:27
 */
public class ClientFactory {
	
	private static ClientFactory clientFactory = new ClientFactory();
	private final ReadWriteLock lock = new ReentrantReadWriteLock();
	private boolean configured = false;		//是否初始化
	private ConcurrentMap<String,ClientAgent> clintQueue = new ConcurrentHashMap<String,ClientAgent>();	//保存已经实例化的客户端
	private final Reconnector reconnector;
	
	private ClientFactory(){
		reconnector = new Reconnector();
	}
	
	public static ClientFactory getInstance(){
		return clientFactory;
	}

	/**
	 * 初始化
	 * @throws Exception
	 */
	public void initiation()throws Exception{
		lock.writeLock().lock();
		try{
			if(!configured){
				reconnector.startReconnect();
				configured = true;
			}
		}catch(Exception e){
			throw e;
		}finally{
			lock.writeLock().unlock();
		}
	}
	
	/**
	 * 销毁
	 * @throws Exception
	 */
	public void destroy() throws Exception{
		lock.writeLock().lock();
		try{
			if(configured){
				//释放资源
				reconnector.stopReconnect();
				releaseAllClient();
				configured = false;
			}
		}catch(Exception e){
			throw e;
		}finally{
			lock.writeLock().unlock();
		}
	}
	
	/**
	 * 新建一个客户端
	 * @param client
	 * @throws Exception 
	 */
	public void createClient(ClientConfig config) throws Exception{
		if(isConfigured()){
			if(clintQueue.get(config.getUniqueKey()) == null){
				ClientAgent agent = new ClientAgentAsynImpl(config);
				clintQueue.put(config.getUniqueKey(), agent);
			}else{
				throw new Exception("client has bean exists:" + config.getUniqueKey());
			}
		}
	}
	
	/**
	 * 释放所有已经实例化的客户端的资源
	 */
	private void releaseAllClient(){
		Iterator iter = clintQueue.entrySet().iterator();
		ClientAgent clientAgent;
		while(iter.hasNext()){
			Map.Entry entry = (Map.Entry) iter.next(); 
			clientAgent = (ClientAgent)entry.getValue();
			clientAgent.release();
		}
		
		clintQueue.clear();
	}

	/**
	 * 是否已经初始化
	 * @return
	 */
	public boolean isConfigured() {
		lock.readLock().lock();
		try{
			return configured;
		}finally{
			lock.readLock().unlock();
		}
	}
	
	/**
	 * 发送数据
	 * @param uniqueKey
	 * @param object
	 * @throws Exception
	 */
	public void sendMessage(String uniqueKey,Object object) throws Exception{
		if(isConfigured()){
			clintQueue.get(uniqueKey).sendMsg(object);
		}else{
			throw new Exception("Configured not initialized");
		}
	}
	
	/**
	 * 发送数据
	 * @param uniqueKey
	 * @param object
	 * @throws Exception
	 */
	public boolean isConnect(String uniqueKey) throws Exception{
		if(isConfigured()){
			return clintQueue.get(uniqueKey).isConnected();
		}else{
			throw new Exception("Configured not initialized");
		}
	}
	
//	/**
//	 * 创建通讯模板
//	 * @return
//	 * @throws Exception
//	 */
//	public MessageTemplate createMessageTemplate() throws Exception{
//		if(isConfigured()){
//			return new MessageTemplate();
//		}else{
//			throw new Exception("Configured not initialized");
//		}
//	}
//	
//	/**
//	 * 创建通讯模板
//	 * @param excutor	执行方式
//	 * @return
//	 * @throws Exception
//	 */
//	public MessageTemplate createMessageTemplate(Excutor excutor) throws Exception{
//		if(isConfigured()){
//			return new MessageTemplate(excutor);
//		}else{
//			throw new Exception("Configured not initialized");
//		}
//	}
	
	
	//重连线程
	public class Reconnector implements Runnable {
		
		private final Thread contorlThread;
		
		public Reconnector(){
			contorlThread = new Thread(this, "Reconnector");
			contorlThread.setDaemon(true);
		}
		
		public void run() {
			while(true){
				processReconnect();
				try {
					Thread.sleep(GateWayConstant.RECONNECTOR_INTERVFAL);
				} catch (InterruptedException e) {
					// Do nothing
				}
			}
		}
		
		private void processReconnect(){
			Iterator iter = clintQueue.entrySet().iterator();
			ClientAgent clientAgent;
			while(iter.hasNext()){
				Map.Entry entry = (Map.Entry) iter.next(); 
				clientAgent = (ClientAgent)entry.getValue();
				if(clientAgent instanceof Reconnectable){
					Reconnectable reconnectable = (Reconnectable)clientAgent;
					reconnectable.reconnect();
				}
			}
		}
		
		public void startReconnect(){
			contorlThread.start();
		}
		
		public void stopReconnect(){
			contorlThread.interrupt();
		}
	}
}
